import java.util.ArrayList;
import java.util.List;

/**
 * 学生选课系统（合并版）
 * 包含父类Person，子类Student/Teacher，课程类Course及测试入口
 */
public class CourseSelectionSystem {

    // ======================== 父类：Person（提取师生共性）========================
    static abstract class Person {
        // 共性属性（private封装，仅通过getter访问）
        private String id;
        private String name;
        private String gender;

        /**
         * 父类构造方法：初始化共性属性
         * 子类需通过super()调用
         */
        public Person(String id, String name, String gender) {
            this.id = id;
            this.name = name;
            this.gender = gender;
        }

        // Getter方法：提供属性访问接口
        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public String getGender() {
            return gender;
        }

        /**
         * 通用方法：打印基础信息
         * protected修饰：允许子类调用/重写
         */
        protected void printBaseInfo() {
            System.out.printf("ID：%s | 姓名：%s | 性别：%s", id, name, gender);
        }

        /**
         * 抽象方法：打印完整信息（子类需实现个性化内容）
         */
        public abstract void printInfo();
    }

    // ======================== 子类：Student（学生功能实现）========================
    static class Student extends Person {
        // 学生特有属性（private封装）
        private String major;
        private List<Course> selectedCourses;

        /**
         * 子类构造方法：调用父类构造+初始化特有属性
         */
        public Student(String studentId, String name, String gender, String major) {
            super(studentId, name, gender); // 必须在第一行调用父类构造
            this.major = major;
            this.selectedCourses = new ArrayList<>();
        }

        // Getter方法：提供特有属性访问接口
        public String getMajor() {
            return major;
        }

        public List<Course> getSelectedCourses() {
            return selectedCourses;
        }

        /**
         * 学生特有功能：选课
         * @param course 待选课程
         * @return 选课成功返回true，失败返回false
         */
        public boolean selectCourse(Course course) {
            // 校验1：是否已选该课程
            if (selectedCourses.contains(course)) {
                System.out.println(getName() + " 已选择课程：" + course.getCourseName());
                return false;
            }
            // 校验2：课程是否已满
            if (course.isFull()) {
                System.out.println("课程 " + course.getCourseName() + " 已满，无法选择");
                return false;
            }
            // 选课成功：更新学生课程列表与课程人数
            selectedCourses.add(course);
            course.addStudent();
            System.out.println(getName() + " 成功选择课程：" + course.getCourseName());
            return true;
        }

        /**
         * 学生特有功能：退课
         * @param course 待退课程
         * @return 退课成功返回true，失败返回false
         */
        public boolean dropCourse(Course course) {
            if (selectedCourses.remove(course)) {
                course.removeStudent();
                System.out.println(getName() + " 成功退选课程：" + course.getCourseName());
                return true;
            } else {
                System.out.println(getName() + " 未选择课程：" + course.getCourseName());
                return false;
            }
        }

        /**
         * 重写父类抽象方法：打印学生课表（个性化实现）
         */
        @Override
        public void printInfo() {
            System.out.println("\n========== " + getName() + " 的课表 ==========");
            printBaseInfo(); // 调用父类方法打印基础信息
            System.out.println(" | 专业：" + major);
            System.out.println("==========================================");

            if (selectedCourses.isEmpty()) {
                System.out.println("当前未选择任何课程");
            } else {
                // 格式化打印课表表头
                System.out.printf("%-10s %-15s %-10s %-10s %-10s\n",
                        "课程编号", "课程名称", "上课地点", "上课时间", "授课教师");
                System.out.println("----------------------------------------------------------");
                // 遍历打印已选课程详情
                for (Course course : selectedCourses) {
                    System.out.printf("%-12s %-15s %-12s %-12s %-10s\n",
                            course.getCourseId(),
                            course.getCourseName(),
                            course.getLocation(),
                            course.getTime(),
                            course.getTeacher().getName());
                }
            }
            System.out.println("==========================================\n");
        }
    }

    // ======================== 子类：Teacher（教师功能实现）========================
    static class Teacher extends Person {
        // 教师特有属性（private封装）
        private String department;
        private Course teachingCourse;

        /**
         * 子类构造方法：调用父类构造+初始化特有属性
         */
        public Teacher(String teacherId, String name, String gender, String department) {
            super(teacherId, name, gender); // 调用父类构造初始化基础属性
            this.department = department;
        }

        // Getter方法：提供特有属性访问接口
        public String getDepartment() {
            return department;
        }

        public Course getTeachingCourse() {
            return teachingCourse;
        }

        /**
         * 教师特有功能：开设课程
         * @param courseId 课程编号
         * @param courseName 课程名称
         * @param location 上课地点
         * @param time 上课时间
         * @param maxStudents 最大选课人数
         * @return 新建的课程对象
         */
        public Course openCourse(String courseId, String courseName, String location, String time, int maxStudents) {
            this.teachingCourse = new Course(courseId, courseName, location, time, this, maxStudents);
            System.out.println("教师 " + getName() + " 成功开设课程：" + courseName);
            return teachingCourse;
        }

        /**
         * 重写父类抽象方法：打印教师授课信息（个性化实现）
         */
        @Override
        public void printInfo() {
            System.out.println("========== " + getName() + " 的授课信息 ==========");
            printBaseInfo(); // 调用父类方法打印基础信息
            System.out.println(" | 部门：" + department);
            System.out.println("==========================================");

            if (teachingCourse != null) {
                System.out.println("授课详情：" + teachingCourse);
            } else {
                System.out.println("当前未开设任何课程");
            }
            System.out.println("==========================================\n");
        }
    }

    // ======================== 课程类：Course（关联师生）========================
    static class Course {
        // 课程属性（private封装）
        private String courseId;
        private String courseName;
        private String location;
        private String time;
        private Teacher teacher; // 关联授课教师
        private int maxStudents; // 最大选课人数
        private int currentStudents; // 当前选课人数

        /**
         * 课程构造方法：初始化课程属性
         */
        public Course(String courseId, String courseName, String location, String time, Teacher teacher, int maxStudents) {
            this.courseId = courseId;
            this.courseName = courseName;
            this.location = location;
            this.time = time;
            this.teacher = teacher;
            this.maxStudents = maxStudents;
            this.currentStudents = 0; // 初始无学生选课
        }

        // Getter方法：提供属性访问接口
        public String getCourseId() {
            return courseId;
        }

        public String getCourseName() {
            return courseName;
        }

        public String getLocation() {
            return location;
        }

        public String getTime() {
            return time;
        }

        public Teacher getTeacher() {
            return teacher;
        }

        public int getMaxStudents() {
            return maxStudents;
        }

        public int getCurrentStudents() {
            return currentStudents;
        }

        // Setter方法：仅允许修改当前人数（控制访问权限）
        public void setCurrentStudents(int currentStudents) {
            this.currentStudents = currentStudents;
        }

        /**
         * 判断课程是否满员
         * @return 满员返回true，否则返回false
         */
        public boolean isFull() {
            return currentStudents >= maxStudents;
        }

        /**
         * 增加选课人数（仅在未满员时生效）
         */
        public void addStudent() {
            if (!isFull()) {
                currentStudents++;
            }
        }

        /**
         * 减少选课人数（仅在有学生时生效）
         */
        public void removeStudent() {
            if (currentStudents > 0) {
                currentStudents--;
            }
        }

        /**
         * 重写toString：打印课程完整信息
         */
        @Override
        public String toString() {
            return String.format("课程编号：%s | 课程名称：%s | 上课地点：%s | 上课时间：%s | 授课教师：%s | 选课人数：%d/%d",
                    courseId, courseName, location, time, teacher.getName(), currentStudents, maxStudents);
        }
    }

    // ======================== 测试入口：main方法 ========================
    public static void main(String[] args) {
        System.out.println("=== 学生选课模拟系统（合并版） ===\n");

        // 1. 创建教师对象
        Teacher teacher1 = new Teacher("T001", "张教授", "男", "计算机科学");
        Teacher teacher2 = new Teacher("T002", "李教授", "女", "数学");
        Teacher teacher3 = new Teacher("T003", "王教授", "男", "物理");

        // 2. 教师开设课程
        System.out.println("=== 步骤1：教师开课 ===");
        Course mathCourse = teacher1.openCourse("C001", "高等数学", "教学楼A101", "周一 8:00-10:00", 30);
        Course javaCourse = teacher2.openCourse("C002", "Java程序设计", "实验楼B201", "周三 14:00-16:00", 25);
        Course physicsCourse = teacher3.openCourse("C003", "大学物理", "教学楼A205", "周五 10:00-12:00", 35);
        System.out.println();

        // 3. 创建学生对象
        Student student1 = new Student("S001", "张三", "男", "计算机科学");
        Student student2 = new Student("S002", "李四", "女", "软件工程");
        Student student3 = new Student("S003", "王五", "男", "信息技术");

        // 4. 学生选课
        System.out.println("=== 步骤2：学生选课 ===");
        student1.selectCourse(mathCourse);
        student1.selectCourse(javaCourse);
        student1.selectCourse(physicsCourse);

        student2.selectCourse(mathCourse);
        student2.selectCourse(javaCourse);

        student3.selectCourse(mathCourse);
        student3.selectCourse(physicsCourse);
        System.out.println();

        // 5. 打印学生课表
        System.out.println("=== 步骤3：打印学生课表 ===");
        student1.printInfo();
        student2.printInfo();
        student3.printInfo();

        // 6. 学生退课
        System.out.println("=== 步骤4：学生退课 ===");
        student1.dropCourse(mathCourse);
        student1.printInfo(); // 退课后重新打印课表

        // 7. 打印教师授课信息
        System.out.println("=== 步骤5：打印教师授课信息 ===");
        teacher1.printInfo();
        teacher2.printInfo();
        teacher3.printInfo();

        // 8. 测试课程满员场景
        System.out.println("=== 步骤6：测试课程满员 ===");
        Course smallCourse = teacher1.openCourse("C004", "小班课程", "教学楼A101", "周二 8:00-10:00", 2);
        Student testStudent1 = new Student("S004", "测试学生1", "男", "测试专业");
        Student testStudent2 = new Student("S005", "测试学生2", "女", "测试专业");
        Student testStudent3 = new Student("S006", "测试学生3", "男", "测试专业");

        testStudent1.selectCourse(smallCourse);
        testStudent2.selectCourse(smallCourse);
        testStudent3.selectCourse(smallCourse); // 预期失败（课程已满）
        System.out.println();

        System.out.println("=== 系统运行结束 ===");
    }
}